﻿namespace FiftyOne.Foundation.Mobile.Detection.Wurfl
{
    using FiftyOne;
    using FiftyOne.Foundation.Mobile.Detection;
    using FiftyOne.Foundation.Mobile.Detection.Wurfl.Configuration;
    using FiftyOne.Foundation.Mobile.Detection.Wurfl.Handlers;
    using FiftyOne.Foundation.Mobile.Detection.Wurfl.Matchers;
    using FiftyOne.Foundation.Mobile.Detection.Wurfl.Matchers.Final;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Web;

    internal class Provider
    {
        private Cache<DeviceInfo> _cache = new Cache<DeviceInfo>(60);
        private static DeviceInfo _defaultDevice = null;
        private Hashtable _deviceIDs = new Hashtable(0x36b0);
        private Handler[] _handlers = null;
        private static Provider _instance;
        private bool _isLoaded = false;
        private static object _staticLock = new object();

        internal Provider()
        {
            this.InitHandlers();
        }

        private DeviceInfo GetActualDeviceRootDeviceInfo(DeviceInfo device)
        {
            DeviceInfo fallbackDevice = device.FallbackDevice;
            if (fallbackDevice != null)
            {
                if (fallbackDevice.IsActualDeviceRoot)
                {
                    return fallbackDevice;
                }
                return this.GetActualDeviceRootDeviceInfo(fallbackDevice);
            }
            return null;
        }

        internal DeviceInfo GetDeviceInfo(string userAgent)
        {
            long num = EventLog.IsDebug ? DateTime.Now.Ticks : 0L;
            DeviceInfo deviceInfo = null;
            if (!string.IsNullOrEmpty(userAgent) && !this._cache.GetTryParse(userAgent, out deviceInfo))
            {
                Handler[] handlers = this.GetHandlers(userAgent);
                if ((handlers != null) && (handlers.Length > 0))
                {
                    deviceInfo = GetDeviceInfo(userAgent, handlers);
                    if (!(!Manager.UseActualDeviceRoot || deviceInfo.IsActualDeviceRoot))
                    {
                        deviceInfo = this.GetActualDeviceRootDeviceInfo(deviceInfo);
                    }
                    if (deviceInfo != null)
                    {
                        this._cache[userAgent] = deviceInfo;
                    }
                }
            }
            if (deviceInfo == null)
            {
                deviceInfo = DefaultDevice;
            }
            return deviceInfo;
        }

        protected internal DeviceInfo GetDeviceInfo(HttpContext context)
        {
            long num = EventLog.IsDebug ? DateTime.Now.Ticks : 0L;
            string userAgent = GetUserAgent(context.Request);
            DeviceInfo deviceInfo = null;
            if (!string.IsNullOrEmpty(userAgent) && !this._cache.GetTryParse(userAgent, out deviceInfo))
            {
                Handler[] handlers = this.GetHandlers(context.Request);
                if ((handlers != null) && (handlers.Length > 0))
                {
                    deviceInfo = GetDeviceInfo(context.Request, handlers);
                    if (!(!Manager.UseActualDeviceRoot || deviceInfo.IsActualDeviceRoot))
                    {
                        deviceInfo = this.GetActualDeviceRootDeviceInfo(deviceInfo);
                    }
                    if (deviceInfo != null)
                    {
                        this.RecordNewDevice(context.Request, deviceInfo);
                        this._cache[userAgent] = deviceInfo;
                    }
                }
            }
            if (deviceInfo == null)
            {
                deviceInfo = DefaultDevice;
            }
            return deviceInfo;
        }

        private static DeviceInfo GetDeviceInfo(string userAgent, Handler[] handlers)
        {
            DeviceInfo device = null;
            Results results = new Results();
            if (EventLog.IsDebug)
            {
                EventLog.Debug(string.Format("Getting device info for useragent '{0}'.", userAgent));
            }
            for (int i = 0; i < handlers.Length; i++)
            {
                Results collection = handlers[i].Match(userAgent);
                if (collection != null)
                {
                    results.AddRange(collection);
                }
            }
            if (results.Count == 1)
            {
                device = results[0].Device;
            }
            else if (results.Count > 1)
            {
                device = FiftyOne.Foundation.Mobile.Detection.Wurfl.Matchers.Final.Matcher.Match(userAgent, results);
            }
            if (device == null)
            {
                device = handlers[0].DefaultDevice;
            }
            return device;
        }

        private static DeviceInfo GetDeviceInfo(HttpRequest request, Handler[] handlers)
        {
            DeviceInfo device = null;
            Results results = new Results();
            if (EventLog.IsDebug)
            {
                EventLog.Debug(string.Format("Getting device info for HttpRequest '{0}'.", GetUserAgent(request)));
            }
            for (int i = 0; i < handlers.Length; i++)
            {
                Results collection = handlers[i].Match(request);
                if (collection != null)
                {
                    results.AddRange(collection);
                }
            }
            if (results.Count == 1)
            {
                device = results[0].Device;
            }
            else if (results.Count > 1)
            {
                device = FiftyOne.Foundation.Mobile.Detection.Wurfl.Matchers.Final.Matcher.Match(GetUserAgent(request), results);
            }
            if (device == null)
            {
                device = handlers[0].DefaultDevice;
            }
            return device;
        }

        protected internal DeviceInfo GetDeviceInfoFromID(string deviceID)
        {
            if (this._deviceIDs.ContainsKey(deviceID))
            {
                return (DeviceInfo) this._deviceIDs[deviceID];
            }
            return null;
        }

        private Handler[] GetHandlers(DeviceInfo device)
        {
            byte highestConfidence = 0;
            List<Handler> handlers = new List<Handler>();
            EventLog.Debug(string.Format("Getting handlers for DeviceId '{0}'.", device.DeviceId));
            foreach (Handler handler in this._handlers)
            {
                if (handler.CanHandle(device))
                {
                    GetHandlers(ref highestConfidence, handlers, handler);
                }
            }
            return handlers.ToArray();
        }

        private Handler[] GetHandlers(string userAgent)
        {
            byte highestConfidence = 0;
            List<Handler> handlers = new List<Handler>();
            if (EventLog.IsDebug)
            {
                EventLog.Debug(string.Format("Getting handlers for useragent '{0}'.", userAgent));
            }
            foreach (Handler handler in this._handlers)
            {
                if (handler.CanHandle(userAgent))
                {
                    GetHandlers(ref highestConfidence, handlers, handler);
                }
            }
            return handlers.ToArray();
        }

        private Handler[] GetHandlers(HttpRequest request)
        {
            byte highestConfidence = 0;
            List<Handler> handlers = new List<Handler>();
            if (EventLog.IsDebug)
            {
                EventLog.Debug(string.Format("Getting handlers for HttpRequest '{0}'.", GetUserAgent(request)));
            }
            foreach (Handler handler in this._handlers)
            {
                if (handler.CanHandle(request))
                {
                    GetHandlers(ref highestConfidence, handlers, handler);
                }
            }
            return handlers.ToArray();
        }

        private static void GetHandlers(ref byte highestConfidence, List<Handler> handlers, Handler handler)
        {
            if (handler.Confidence > highestConfidence)
            {
                handlers.Clear();
                handlers.Add(handler);
                highestConfidence = handler.Confidence;
            }
            else if (handler.Confidence == highestConfidence)
            {
                handlers.Add(handler);
            }
        }

        protected internal static string GetUserAgent(HttpRequest request)
        {
            string userAgent = request.UserAgent;
            foreach (string str2 in FiftyOne.Foundation.Mobile.Detection.Constants.TRANSCODER_USERAGENT_HEADERS)
            {
                if (request.Headers[str2] != null)
                {
                    userAgent = request.Headers[str2];
                    break;
                }
            }
            if (userAgent == null)
            {
                return string.Empty;
            }
            return userAgent.Trim();
        }

        private void InitHandlers()
        {
            List<Handler> list = new List<Handler>();
            list.Add(new AlcatelHandler());
            list.Add(new AlphaHandlerAtoF());
            list.Add(new AlphaHandlerGtoN());
            list.Add(new AlphaHandlerOtoS());
            list.Add(new AlphaHandlerTtoZ());
            list.Add(new AmoiHandler());
            list.Add(new AndriodHandler());
            list.Add(new AOLHandler());
            list.Add(new AppleHandler());
            list.Add(new AppleCoreMediaHandler());
            list.Add(new AvantHandler());
            list.Add(new BenQHandler());
            list.Add(new BlackBerryHandler());
            list.Add(new BirdHandler());
            list.Add(new BoltHandler());
            list.Add(new BrewHandler());
            list.Add(new CatchAllHandler());
            list.Add(new DoCoMoHandler());
            list.Add(new FirefoxHandler());
            list.Add(new GrundigHandler());
            list.Add(new HTCHandler());
            list.Add(new iTunesHandler());
            list.Add(new KDDIHandler());
            list.Add(new KyoceraHandler());
            list.Add(new LCTHandler());
            list.Add(new LGHandler());
            list.Add(new MaxonHandler());
            list.Add(new MitsubishiHandler());
            list.Add(new MobileCatchAllHandler());
            list.Add(new MobileSafariHandler());
            list.Add(new MotorolaHandler());
            list.Add(new MSIEHandler());
            list.Add(new NecHandler());
            list.Add(new NokiaHandler());
            list.Add(new NumericHandler());
            list.Add(new OperaHandler());
            list.Add(new OperaMiniHandler());
            list.Add(new OperaMobiHandler());
            list.Add(new PalmHandler());
            list.Add(new PanasonicHandler());
            list.Add(new PantechHandler());
            list.Add(new PhilipsHandler());
            list.Add(new PortalmmmHandler());
            list.Add(new QtekHandler());
            list.Add(new SafariHandler());
            list.Add(new SagemHandler());
            list.Add(new SamsungHandler());
            list.Add(new SanyoHandler());
            list.Add(new SendoHandler());
            list.Add(new SharpHandler());
            list.Add(new SiemensHandler());
            list.Add(new SoftBankHandler());
            list.Add(new SonyEricssonHandler());
            list.Add(new SPVHandler());
            list.Add(new TianyuHandler());
            list.Add(new ToshibaHandler());
            list.Add(new VodafoneHandler());
            list.Add(new WindowsCEHandler());
            list.Add(new ZuneHandler());
            list.Add(new ChromeHandler());
            list.Add(new FirefoxDesktopHandler());
            list.Add(new MSIEDesktopHandler());
            list.Add(new OperaDesktopHandler());
            list.Add(new SafariDesktopHandler());
            this._handlers = list.ToArray();
        }

        private static bool IsHandler(Type type)
        {
            return ((type == typeof(Handler)) || ((type.BaseType != null) && IsHandler(type.BaseType)));
        }

        protected internal static bool IsMobileDevice(HttpContext context)
        {
            DeviceInfo deviceInfo = Instance.GetDeviceInfo(context);
            return ((deviceInfo != null) && deviceInfo.IsMobileDevice);
        }

        private static void LoadSingleton()
        {
            Provider devices = new Provider();
            try
            {
                long ticks = DateTime.Now.Ticks;
                WurflProcessor.ParseWurflFiles(devices);
                long milliseconds = TimeSpan.FromTicks((DateTime.Now.Ticks - ticks) + 1L).Milliseconds;
                EventLog.Info(string.Format("Loaded {0} devices using {1} strings in {2}ms", devices._deviceIDs.Count, Strings.Count, milliseconds));
                if ((devices._handlers != null) && EventLog.IsDebug)
                {
                    for (int i = 0; i < devices._handlers.Length; i++)
                    {
                        EventLog.Debug(string.Format("Handler '{0}' loaded with {1} devices.", devices._handlers[i].GetType().Name, devices._handlers[i].UserAgents.Count));
                    }
                }
                devices._isLoaded = true;
                _instance = devices;
            }
            catch (WurflException exception)
            {
                EventLog.Fatal(exception);
                _instance = new Provider();
            }
        }

        private void RecordNewDevice(HttpRequest request, DeviceInfo device)
        {
            if (((device.UserAgent != GetUserAgent(request)) && (device != DefaultDevice)) && WurflNewDevice.Enabled)
            {
                DeviceInfo info = new DeviceInfo(this, GetUserAgent(request), GetUserAgent(request), device);
                WurflNewDevice.RecordNewDevice(request);
            }
        }

        internal void Set(DeviceInfo device)
        {
            lock (this._deviceIDs)
            {
                if (this._deviceIDs.ContainsKey(device.DeviceId))
                {
                    this._deviceIDs[device.DeviceId] = device;
                }
                else
                {
                    this._deviceIDs.Add(device.DeviceId, device);
                }
            }
            if (!string.IsNullOrEmpty(device.UserAgent))
            {
                foreach (Handler handler in this.GetHandlers(device))
                {
                    if (handler != null)
                    {
                        handler.Set(device);
                    }
                }
            }
        }

        internal int Count
        {
            get
            {
                return this._deviceIDs.Count;
            }
        }

        internal static DeviceInfo DefaultDevice
        {
            get
            {
                if (_defaultDevice == null)
                {
                    lock (_staticLock)
                    {
                        if (_defaultDevice == null)
                        {
                            foreach (string str in FiftyOne.Foundation.Mobile.Detection.Wurfl.Constants.DefaultDeviceId)
                            {
                                _defaultDevice = Instance.GetDeviceInfoFromID(str);
                                if (_defaultDevice != null)
                                {
                                    goto Label_0083;
                                }
                            }
                        }
                    }
                }
            Label_0083:
                return _defaultDevice;
            }
        }

        internal static Provider Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_staticLock)
                    {
                        if (_instance == null)
                        {
                            LoadSingleton();
                        }
                    }
                }
                return _instance;
            }
        }

        internal bool IsLoaded
        {
            get
            {
                return this._isLoaded;
            }
        }
    }
}

